#ifndef MERGE_H
#define MERGE_H

#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

#include "termino_merge.h"
#include "buffer_merge.h"
#include "cola.h"
#include "abb_avl.h"
#include "heap.h"
#include "utilidades.h"

// Tamanios en MiB
#define TAM_PARTICION 30
#define TAM_BUFFER 100

/** ***********							*********** **
 ** ***********	ESTRUCTURAS AUXILIARES	*********** **
 ** ***********							*********** **/					

/*
 * Crea y devuelve una lista de n colas. Devuelve la lista de colas,
 * o NULL si no pudo crear alguna de ellas.
 */
cola_t** crear_lista_de_colas(unsigned long numero_de_colas);

/*
 * Destruye una lista de n colas.
 */
void destruir_lista_de_colas(cola_t** lista_colas, unsigned long numero_de_colas);

/*
 * Funcion de comparacion utilizada por el heap.
 */
int comparar_claves(const void* termino1,const void* termino2);

/** ***********							*********** **
 ** ***********		MERGE DE ARCHIVOS	*********** **
 ** ***********							*********** **/	

/* 
 * Hace un merge de los n primeros archivos de la lista de archivos recibidos.
 * Escribe en el archivo dest.
 */
buffer_t* merge_lista_archivos(FILE** lista_archivos,unsigned long numero_archivos,FILE* destino);

/*
 * Devuelve el término menor alfabéticamente de entre las colas recibidas.
 * Llena las colas si estas se han terminado. Recibe el máximo tamanio
 * que puede ocupar una cola en memoria. Devuelve el menor término o NULL
 * si no hay más términos en los archivos que se está procesando.
 */
termino_merge_t* obtener_menor_termino(heap_t* terminos_con_id,FILE** lista_archivos,cola_t** lista_colas,unsigned long numero_archivos,unsigned long tamanio_particion);

/*
 * Desencola un elemento de la cola recibido en el heap recibido. Si la cola
 * esta vacia, intenta llenarla con el archivo recibido. Si el archivo esta
 * en condicion de end of file, sale de la funcion. Si pudo desencolar un elemento
 * de la cola, se agrega este al heap.
 */
void desencolar_en_heap(heap_t* terminos_con_id,FILE* archivo,cola_t* cola,unsigned long tamanio_particion,unsigned long id);

/*
 * Llena de elementos (termino,aparicion,documento) la cola recibida,
 * obteniendo los mismos del archivo ordenado por termino. Llena esta
 * cola hasta llegar a un determinado tamanio en memoria.
 * Devuelve true si la pudo llenar o false en caso contrario.
 */
bool llenar_cola(FILE* archivo,cola_t* cola,unsigned long tamanio_particion,unsigned long id);

/*
 * Carga el heap a partir de una lista de colas. Agrega una cantidad fija
 * de elementos de cada cola (si es que esta tiene esta cantidad de elementos).
 * Si la cola se queda sin elementos, se trata de llenarla a partir de su subarchivo
 * correspondiente, recibido en la lista de archivos, por parámetro.
 */
void llenar_heap(heap_t* heap,FILE** lista_archivos,unsigned long numero_archivos,cola_t** lista_colas,unsigned long tamanio_particion);

/*
 * Llena la lista de n colas recibidas a partir de la lista de archivos recibidos.
 * Devuelve true si las pudo llenar a todas o false en caso contrario.
 */
void llenar_colas(FILE** lista_archivos,unsigned long numero_archivos,cola_t** lista_colas,unsigned long tamanio_particion);

/*
 * Vuelca el avl a un subarchivo, con el formato que discutimos (termino,repeticiones).
 */
void escribir_termino_a_archivo(FILE* destino, termino_merge_t* term);

/**	*********						********* **
 ** *********	MERGE DE DOS FASES	********* **
 ** *********						********* **/

/*
 * Realiza un merge de dos fases. El nombre del archivo final destino
 * se recibe por parametro. La cantidad de subarchivos a mergear
 * tambien se recibe por parametro. Los nombres de los subarchivos a
 * mergear deben ser siguiendo el siguiente formato:
 * subarchivo-n, donde n es un numero entre [0,cantidad).
 * Devuelve el buffer en su estado final luego de completar el merge.
 */
buffer_t* merge_dos_fases(char* merge_file,unsigned long cantidad);

#endif // MERGE_H

